package com.geovis.emergency.spd.biz.pc.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geovis.common.auth.util.AuthUtil;
import com.geovis.emergency.spd.biz.basic.mapper.BasicDutyOrgMapper;
import com.geovis.emergency.spd.biz.pc.mapper.*;
import com.geovis.emergency.spd.biz.pc.service.IPcDisasterEventService;
import com.geovis.emergency.spd.biz.pc.service.IPcDrillDutyOrgService;
import com.geovis.emergency.spd.biz.pc.service.IPcDrillPlanService;
import com.geovis.emergency.spd.biz.system.service.ISystemFileBusinessService;
import com.geovis.emergency.spd.biz.system.service.ISystemFileService;
import com.geovis.emergency.spd.cache.UserCache;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcDrillConstant;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcMessageConstant;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcDrillPlanApprovalDTO;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcDrillPlanDetailDTO;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcDrillPlanSaveDTO;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcDrillPlanUpdateDTO;
import com.geovis.emergency.spd.entity.pc.pojo.enums.CheckStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.enums.TaskStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillPlanDetailUsersVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillPlanDetailVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillPlanVO;
import com.geovis.emergency.spd.entity.system.constant.SystemFileBusinessConstant;
import com.geovis.emergency.spd.entity.system.entity.SystemFile;
import com.geovis.emergency.spd.entity.system.entity.SystemFileBusiness;
import com.geovis.emergency.spd.entity.system.entity.SystemUser;
import com.geovis.emergency.spd.entity.system.pojo.dto.SystemFileDTO;
import com.geovis.emergency.spd.entity.system.pojo.dto.SystemFileQueryDTO;
import com.geovis.emergency.spd.util.MsgUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 应急预案指挥模块-演练工作方案 服务实现类
 * </p>
 *
 * @author Lonsho
 * @since 2022-06-08
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PcDrillPlanServiceImpl extends ServiceImpl<PcDrillPlanMapper, PcDrillPlan> implements IPcDrillPlanService {
    private final ISystemFileBusinessService systemFileBusinessService;
    private final ISystemFileService systemFileService;
    private final PcDrillPlanApprovalMapper pcDrillPlanApprovalMapper;
    private final PcDrillPlanTaskMapper pcDrillPlanTaskMapper;
    private final PcDrillPlanTaskApprovalMapper pcDrillPlanTaskApprovalMapper;
    private final IPcDisasterEventService pcDisasterEventService;

    private final PcDrillDutyOrgMapper pcDrillDutyOrgMapper;
    private final PcDrillDutyUserMapper pcDrillDutyUserMapper;
    private final PcDrillPlanDetailMapper pcDrillPlanDetailMapper;

    private final BasicDutyOrgMapper basicDutyOrgMapper;
    private final PcDrillMapper pcDrillMapper;

    private final IPcDrillDutyOrgService pcDrillDutyOrgService;

    private void checkPcDrill(String drillId) {
        PcDrill pcDrill = pcDrillMapper.selectById(drillId);
        Assert.notNull(pcDrill, "演练不存在");
        Assert.isFalse(PcDrillConstant.STATUS_COMPLETE.equals(pcDrill.getStatus()), "该演练已经结束了");
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PcDrillPlanVO savePcDrillPlan(PcDrillPlanSaveDTO saveDTO) {
        checkPcDrill(saveDTO.getPcDrillId());
        PcDrillPlanVO pcDrillPlan = BeanUtil.toBean(saveDTO,PcDrillPlanVO.class);
        pcDrillPlan.setPcPlanId(saveDTO.getPlanId());
        pcDrillPlan.setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode());
        baseMapper.insert(pcDrillPlan);
        if (ObjectUtil.isNotEmpty(saveDTO.getFileList())){
            Set<SystemFileBusiness> fileBusinessSet = CollUtil.set(false);
            //关联业务附件
            saveDTO.getFileList().forEach(systemFile ->
                    fileBusinessSet.add(new SystemFileBusiness(systemFile.getId(), SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK, pcDrillPlan.getId())));
            systemFileBusinessService.saveBatch(fileBusinessSet);
        }

        //演练详情
        for (PcDrillPlanDetailDTO pcDrillPlanDetailDTO : saveDTO.getDetailList()) {
            PcDrillPlanDetail pcDrillPlanDetail = BeanUtil.toBean(pcDrillPlanDetailDTO,PcDrillPlanDetail.class);
            pcDrillPlanDetail.setPcPlanId(saveDTO.getPlanId());
            pcDrillPlanDetail.setPcDrillId(saveDTO.getPcDrillId());
            pcDrillPlanDetail.setGroupId(saveDTO.getGroupId());
            pcDrillPlanDetail.setPcDrillPlanId(pcDrillPlan.getId());
            pcDrillPlanDetail.setPcDrillDisasterEventId(pcDrillPlan.getPcDrillDisasterEventId());
            pcDrillPlanDetail.setPcDrillDisasterId(pcDrillPlan.getPcDrillDisasterId());
            pcDrillPlanDetail.setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode());
            pcDrillPlanDetailMapper.insert(pcDrillPlanDetail);
        }
        //保存审核记录
        PcDrillPlanApproval pcDrillPlanApproval = new PcDrillPlanApproval()
                .setPcDrillId(saveDTO.getPcDrillId())
                .setContent("提交审核")
                .setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode())
                .setPcDrillPlanId(pcDrillPlan.getId())
                .setPcDrillDisasterId(pcDrillPlan.getPcDrillDisasterId())
                .setPcDrillDisasterEventId(pcDrillPlan.getPcDrillDisasterEventId())
                .setAuditId(AuthUtil.getCurrentUserId())
                .setApprovalTime(LocalDateTime.now());
        pcDrillPlanApprovalMapper.insert(pcDrillPlanApproval);
        PcDrillDutyOrg pcDrillDutyOrg = pcDrillDutyOrgMapper.selectById(saveDTO.getGroupId());
        pcDrillPlan.setOrgName(pcDrillDutyOrg.getOrgName());
        return pcDrillPlan;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PcDrillPlanVO updatePcDrillPlan(PcDrillPlanUpdateDTO updateDTO) {
        checkPcDrill(updateDTO.getPcDrillId());
        PcDrillPlan pcDrillPlan = baseMapper.selectById(updateDTO.getId());
        Assert.notNull(pcDrillPlan, "演练方案不存在");
        BeanUtil.copyProperties(updateDTO,pcDrillPlan);
        pcDrillPlan.setPcDrillId(updateDTO.getPcDrillId());
        pcDrillPlan.setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode());
        baseMapper.updateById(pcDrillPlan);
        if (ObjectUtil.isNotEmpty(updateDTO.getFileList())){

            List<String> fileIdList = updateDTO.getFileList().stream().map(SystemFile::getId).collect(Collectors.toList());
            //将已经前端已经删除的文件删除掉
            LambdaQueryWrapper<SystemFileBusiness> updateWrapper = Wrappers.<SystemFileBusiness>lambdaQuery()
                    .eq(SystemFileBusiness::getRelatedId, pcDrillPlan.getId())
                    .eq(SystemFileBusiness::getType, SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK)
                    .notIn(SystemFileBusiness::getFileId, fileIdList);
            systemFileBusinessService.remove(updateWrapper);

            Set<SystemFileBusiness> fileBusinessSet = CollUtil.set(false);
            //关联业务附件
            updateDTO.getFileList().forEach(systemFile -> {
                if (systemFileBusinessService.count(Wrappers.<SystemFileBusiness>lambdaQuery()
                        .eq(SystemFileBusiness::getFileId,systemFile.getId())
                        .eq(SystemFileBusiness::getRelatedId, pcDrillPlan.getId())
                        .eq(SystemFileBusiness::getType, SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK)) == 0){
                    fileBusinessSet.add(new SystemFileBusiness(systemFile.getId(), SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK, pcDrillPlan.getId()));
                }
            });
            systemFileBusinessService.saveBatch(fileBusinessSet);
        }
        PcDrillPlanVO pcDrillPlanVO = BeanUtil.toBean(pcDrillPlan,PcDrillPlanVO.class);
        pcDrillPlanVO.setFileList(updateDTO.getFileList());

        List<String> detailIdList = updateDTO.getDetailList().stream().map(PcDrillPlanDetailDTO::getId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(detailIdList)) {
            pcDrillPlanDetailMapper.delete(
                    Wrappers.lambdaQuery(PcDrillPlanDetail.class)
                            .eq(PcDrillPlanDetail::getPcDrillId,updateDTO.getPcDrillId())
                            .eq(PcDrillPlanDetail::getPcDrillPlanId,pcDrillPlan.getId())
                            .notIn(PcDrillPlanDetail::getId,detailIdList)
            );
        }
        //演练详情
        for (PcDrillPlanDetailDTO pcDrillPlanDetailDTO : updateDTO.getDetailList()) {
            PcDrillPlanDetail pcDrillPlanDetail = BeanUtil.toBean(pcDrillPlanDetailDTO,PcDrillPlanDetail.class);
            pcDrillPlanDetail.setPcDrillId(updateDTO.getPlanId());
            pcDrillPlanDetail.setPcDrillId(updateDTO.getPcDrillId());
            pcDrillPlanDetail.setGroupId(updateDTO.getGroupId());
            pcDrillPlanDetail.setPcDrillPlanId(pcDrillPlan.getId());
            pcDrillPlanDetail.setPcDrillDisasterEventId(pcDrillPlan.getPcDrillDisasterEventId());
            pcDrillPlanDetail.setPcDrillDisasterId(pcDrillPlan.getPcDrillDisasterId());
            pcDrillPlanDetail.setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode());
            if (ObjectUtil.isNotNull(pcDrillPlanDetail.getId())){
                pcDrillPlanDetailMapper.updateById(pcDrillPlanDetail);
            }else {
                pcDrillPlanDetailMapper.insert(pcDrillPlanDetail);
            }
        }
        //保存审核记录
        PcDrillPlanApproval pcDrillPlanApproval = new PcDrillPlanApproval()
                .setPcDrillId(pcDrillPlan.getPcDrillId())
                .setContent("提交审核")
                .setStatus(CheckStatusEnum.WAIT_APPROVAL.getCode())
                .setPcDrillPlanId(pcDrillPlan.getId())
                .setPcDrillId(pcDrillPlan.getPcDrillId())
                .setPcDrillDisasterId(pcDrillPlan.getPcDrillDisasterId())
                .setPcDrillDisasterEventId(pcDrillPlan.getPcDrillDisasterEventId())
                .setAuditId(AuthUtil.getCurrentUserId())
                .setApprovalTime(LocalDateTime.now());
        pcDrillPlanApprovalMapper.insert(pcDrillPlanApproval);

        PcDrillDutyOrg pcDrillDutyOrg = pcDrillDutyOrgMapper.selectById(updateDTO.getGroupId());

        pcDrillPlanVO.setOrgName(pcDrillDutyOrg.getOrgName());
        return pcDrillPlanVO;
    }
    @Override
    public List<PcDrillPlanVO> pcDrillPlanList(String drillId, String drillDisasterEventId,String groupId, String status) {
       List<PcDrillPlan> list = baseMapper.selectList(
               Wrappers.<PcDrillPlan>lambdaQuery()
                       .eq(PcDrillPlan::getPcDrillId,drillId)
                       .eq(PcDrillPlan::getPcDrillDisasterEventId,drillDisasterEventId)
                       .eq(StrUtil.isNotBlank(groupId),PcDrillPlan::getGroupId,groupId)
                       .in(StrUtil.isNotBlank(status), PcDrillPlan::getStatus,StrUtil.split(status,","))
       );
       return list.stream().map(pcDrillPlan -> {
           PcDrillPlanVO pcDrillPlanVO = BeanUtil.toBean(pcDrillPlan,PcDrillPlanVO.class);
           List<SystemFile> fileList = systemFileService.getListById(pcDrillPlan.getId(),SystemFileBusinessConstant.TYPE_PC_DRILL_PLAN_TASK);
           fileList.sort(Comparator.comparing(SystemFile::getCreateTime));
           pcDrillPlanVO.setFileList(fileList);
           List<PcDrillPlanDetail> pcDrillPlanDetails = pcDrillPlanDetailMapper.selectList(
                   Wrappers.lambdaQuery(PcDrillPlanDetail.class)
                           .eq(PcDrillPlanDetail::getPcDrillPlanId, pcDrillPlan.getId())
           );
           List<PcDrillPlanDetailVO> pcDrillPlanDetailVOList = pcDrillPlanDetails.stream().map(pcDrillPlanDetail -> {
               PcDrillPlanDetailVO pcDrillPlanDetailVO = BeanUtil.toBean(pcDrillPlanDetail, PcDrillPlanDetailVO.class);
               //方案审核通过了，查看任务反馈状态
               if (CheckStatusEnum.PASS.getCode().equals(pcDrillPlanDetailVO.getStatus())) {
                   PcDrillPlanTask pcDrillPlanTask = pcDrillPlanTaskMapper.selectOne(
                           Wrappers.<PcDrillPlanTask>lambdaQuery()
                                   .eq(PcDrillPlanTask::getPcDrillId, pcDrillPlanDetailVO.getPcDrillId())
                                   .eq(PcDrillPlanTask::getPcDrillPlanId, pcDrillPlanDetailVO.getPcDrillPlanId())
                                   .eq(PcDrillPlanTask::getPcDrillPlanDetailId, pcDrillPlanDetailVO.getId())
                                   .eq(PcDrillPlanTask::getPcDrillDisasterEventId, pcDrillPlanDetailVO.getPcDrillDisasterEventId())
                                   .orderByDesc(PcDrillPlanTask::getCreateTime)
                                   .last("limit 1")
                   );

                   if (ObjectUtil.isNotNull(pcDrillPlanTask)) {
                       pcDrillPlanDetailVO.setFeedbackStatus(pcDrillPlanTask.getStatus());
                   } else {
                       pcDrillPlanDetailVO.setFeedbackStatus(TaskStatusEnum.WAIT_COMMIT.getCode());
                   }
               }
               return pcDrillPlanDetailVO;
           }).collect(Collectors.toList());
           pcDrillPlanVO.setDetailList(pcDrillPlanDetailVOList);

           //查询退审记录
           List<PcDrillPlanApproval> pcDrillPlanApprovals = pcDrillPlanApprovalMapper.selectList(
                   Wrappers.<PcDrillPlanApproval>lambdaQuery()
                           .eq(PcDrillPlanApproval::getPcDrillId, pcDrillPlan.getPcDrillId())
                           .eq(PcDrillPlanApproval::getPcDrillPlanId, pcDrillPlan.getId())
                           .eq(PcDrillPlanApproval::getStatus, CheckStatusEnum.REJECT.getCode())
                           .eq(PcDrillPlanApproval::getPcDrillDisasterEventId, pcDrillPlan.getPcDrillDisasterEventId())
                           .orderByDesc(PcDrillPlanApproval::getCreateTime)
           );
           pcDrillPlanVO.setRejectList(pcDrillPlanApprovals);
           PcDrillDutyOrg org=pcDrillDutyOrgService.getById(pcDrillPlan.getGroupId());
           if(org!=null)
           {
               pcDrillPlanVO.setGroupName(org.getOrgName());
               if(StringUtils.hasText(org.getDuty()))
               {
                   pcDrillPlanVO.setPlanDuty(org.getDuty());
               }
               else
               {
                   pcDrillPlanVO.setPlanDuty("负责划定警戒区域，实施现场管控，避免发生二次灾害事故；属地政府或应急管理部门根据灾险情类别，按照就近调用和先专业救援队伍后部队原则组织现场抢险救援队伍。");
               }

           }

//           pcDrillPlanVO.setPlanDuty(pcDrillDutyOrgService.getGroupDuty(drillId,pcDrillPlan.getGroupId()));
           //目前职责只有在pc_plan_duty_dept中有，不是在同步过来的海政通机构有，所以这里先暂时写死
           return pcDrillPlanVO;
       }).collect(Collectors.toList());
    }

    @Override
    public List<PcDrillPlanDetailUsersVO> getSelectUsers(String drillId) {
        return pcDrillDutyOrgService.getUsers4WorkPlan(drillId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<PcDrillPlanDetail> approve(PcDrillPlanApprovalDTO approvalDTO) {

        PcDrillPlan pcDrillPlan = baseMapper.selectById(approvalDTO.getDrillPlanId());
        Assert.notNull(pcDrillPlan,"演练方案不存在");
        checkPcDrill(pcDrillPlan.getPcDrillId());
        if (approvalDTO.getPass()){
            //通过审核
            pcDrillPlan.setStatus(CheckStatusEnum.PASS.getCode());
            approvalDTO.setRejectReason(CheckStatusEnum.PASS.getMsg());
        }else {
            //退审
            pcDrillPlan.setStatus(CheckStatusEnum.REJECT.getCode());
            Assert.notBlank(approvalDTO.getRejectReason(),"退审原因不能为空");
        }
        pcDrillPlan.setAuditId(AuthUtil.getCurrentUserId());
        pcDrillPlan.setAuditName(AuthUtil.getCurrentUsername());
        pcDrillPlan.setAuditTime(LocalDateTime.now());
        baseMapper.updateById(pcDrillPlan);
        //保存审核记录
        PcDrillPlanApproval pcDrillPlanApproval = new PcDrillPlanApproval()
                .setPcDrillId(pcDrillPlan.getPcDrillId())
                .setContent(approvalDTO.getRejectReason())
                .setStatus(pcDrillPlan.getStatus())
                .setPcDrillPlanId(pcDrillPlan.getId())
                .setPcDrillDisasterId(pcDrillPlan.getPcDrillDisasterId())
                .setPcDrillDisasterEventId(pcDrillPlan.getPcDrillDisasterEventId())
                .setAuditId(AuthUtil.getCurrentUserId())
                .setApprovalTime(LocalDateTime.now());
        pcDrillPlanApprovalMapper.insert(pcDrillPlanApproval);

        List<PcDrillPlanDetail> pcDrillPlanDetails = pcDrillPlanDetailMapper.selectList(
                Wrappers.lambdaQuery(PcDrillPlanDetail.class)
                        .eq(PcDrillPlanDetail::getPcDrillPlanId, pcDrillPlan.getId())
        );
        for (PcDrillPlanDetail pcDrillPlanDetail : pcDrillPlanDetails) {
            pcDrillPlanDetail.setStatus(pcDrillPlan.getStatus());
            pcDrillPlanDetailMapper.updateById(pcDrillPlanDetail);
        }
        return pcDrillPlanDetails;
    }

    @Override
    public String dutyGroup(String drillId, String groupId) {
        List<PcDrillDutyOrg> list = pcDrillDutyOrgMapper.selectList(
                Wrappers.lambdaQuery(PcDrillDutyOrg.class)
                        .and(StrUtil.isNotBlank(groupId),
                                s -> s.eq(PcDrillDutyOrg::getId,groupId).or().like(PcDrillDutyOrg::getAncestors,groupId))
                        .eq(PcDrillDutyOrg::getPcDrillId, drillId));
        if (ObjectUtil.isNotEmpty(list)){

            List<PcDrillDutyUser> dutyUserList = pcDrillDutyUserMapper.selectList(
                    Wrappers.lambdaQuery(PcDrillDutyUser.class)
                            .isNotNull(PcDrillDutyUser::getDuty)
                            .in(PcDrillDutyUser::getPcDrillOrgId, list.stream().map(PcDrillDutyOrg::getId).collect(Collectors.toList()))
            );
            Map<String, List<PcDrillDutyUser>> stringListMap = IterUtil.toListMap(dutyUserList, PcDrillDutyUser::getDeptName);
            StringBuilder stringBuilder = new StringBuilder();
            int index = 0;
            for (Map.Entry<String, List<PcDrillDutyUser>> entry : stringListMap.entrySet()) {
                stringBuilder.append(++index).append(".");
                stringBuilder.append(entry.getKey()).append("：");
                Set<String> contentList = entry.getValue().stream().map(PcDrillDutyUser::getDuty).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
                for (String content : contentList) {
                    stringBuilder.append(content.trim()).append("；");
                }
                stringBuilder.append("\n");
            }
            return stringBuilder.toString();
        }
        else {
            return null;
        }
    }
}
